{-# LANGUAGE TypeFamilies               #-}
{-# OPTIONS -Wall #-}


-- Acknowledgment - the Arrow diagram is taken from Ross 
-- Paterson\'s slides /Arrows and Computation/.

-- NOTE - this example now rather out-of-date. Wumpus-Drawing has 
-- some new features to make node/connector drawing a bit easier.

module ArrowCircuit where

import Wumpus.Drawing.Connectors
import qualified Wumpus.Drawing.Connectors.ConnectorPaths as C
import Wumpus.Drawing.Shapes
import Wumpus.Drawing.Text.DirectionZero
import Wumpus.Drawing.Text.StandardFontDefs

import Wumpus.Basic.Kernel                      -- package: wumpus-basic
import Wumpus.Basic.System.FontLoader

import Wumpus.Core                              -- package: wumpus-core


import Data.AffineSpace                         -- package: vector-space

import System.Directory


main :: IO ()
main = simpleFontLoader main1 >> return ()

main1 :: FontLoader -> IO ()
main1 loader = do
    createDirectoryIfMissing True "./out/"    
    base_metrics <- loader [ Right times_roman_family ]
    printLoadErrors base_metrics
    let pic1 = runCtxPictureU (makeCtx base_metrics) circuit_pic
    writeEPS "./out/arrow_circuit.eps" pic1
    writeSVG "./out/arrow_circuit.svg" pic1 

 
makeCtx :: FontLoadResult -> DrawingContext
makeCtx = set_font times_roman . metricsContext 11



-- Note - quite a bit of this diagram was produced /by eye/, 
-- rather than using anchors directly - e.g. the placing of the 
-- ptext labels and the anchors displaced by vectors.
--

-- Note `at` currently does not work for Shapes.
         
circuit_pic :: CtxPicture
circuit_pic = drawTracing body 

body :: TraceDrawing Double ()
body = do
    a1 <- drawi $ rrectangle 12 66 30 `at` P2 0 72
    atext a1 "CONST 0"
    a2 <- drawi $ (strokedShape $ circle 16) `at` P2 120 60
    atext a2 "IF"
    a3 <- drawi $ (strokedShape $ circle 16) `at` P2 240 28
    atext a3 "+1"
    a4 <- drawi $ (strokedShape $ rectangle 66 30) `at` P2 120 0
    atext a4 "DELAY 0"
    connWith conn_line (east a1) ((.+^ hvec 76) $ east a1)
    connWith conn_line (east a2) ((.+^ hvec 180) $ east a2)
    connWith conn_line ((.+^ vvec 40) $ north a2) (north a2)
    connWith conn_line ((.+^ vvec 16) $ north a3) (north a3)  
    connWith conna_right  (south a3) (east a4)
    connWith conna_orthovbar    (west a4)  (southwest a2)
    ptext (P2  40  10) "next"
    ptext (P2 152 100) "reset"
    ptext (P2 252  72) "output"
    return ()

    -- Note - need a variant of /bar/ that draws UDLR only.

connWith :: ( Real u, Floating u, InterpretUnit u ) 
         => ArrowConnector u -> Anchor u -> Anchor u -> TraceDrawing u ()
connWith con a0 a1 = localize double_point_size $ 
    drawc a0 a1 (ignoreAns con)


atext :: ( CenterAnchor (t u), u ~ DUnit (t u)
         , Real u, Floating u, InterpretUnit u)
      => t u -> String -> TraceDrawing u ()
atext ancr ss = 
    draw $ textline CENTER ss `at` (center ancr)


ptext :: (Floating u, InterpretUnit u) 
      => Point2 u -> String -> TraceDrawing u ()
ptext pt ss = localize (font_attr times_italic 14) $ 
    draw $ textline CENTER ss `at` pt


-- Note - return type is a LocImage not a shape...
--
rrectangle :: (Real u, Floating u, InterpretUnit u, Tolerance u) 
           => Double -> u -> u -> LocImage u (Rectangle u)
rrectangle _r w h = strokedShape (rectangle w h)
    -- This should have round corners but they are currently
    -- disabled pending a re-think. 
    {- localize (round_corner_factor r) $ -} 



-- Cf. Parsec\'s Token module...

conn_line :: (Real u, Floating u, InterpretUnit u, Tolerance u) 
          => ArrowConnector u
conn_line =
    renderConnectorConfig default_connector_props $ makeSglArrConn C.conn_line

conna_orthovbar :: (Real u, Floating u, InterpretUnit u, Tolerance u) 
          => ArrowConnector u
conna_orthovbar = 
    renderConnectorConfig default_connector_props $ 
      makeSglArrConn C.conna_orthovbar


conna_right :: (Real u, Floating u, InterpretUnit u, Tolerance u) 
            => ArrowConnector u
conna_right = 
    renderConnectorConfig default_connector_props $ makeSglArrConn C.conna_right


makeSglArrConn :: ConnectorPathSpec u -> ConnectorConfig u
makeSglArrConn cspec = 
    ConnectorConfig
      { conn_arrowl     = Nothing
      , conn_arrowr     = Just tri45
      , conn_path_spec  = cspec
      }
